package cl.movix.usuarios.benchmarks.rates;

import java.text.DecimalFormat;

import org.apache.log4j.Logger;

public class Rater extends Thread {

	/** Logger for this class */
	private static Logger logger = Logger.getLogger(Rater.class);

	/** The object to be measured */
	private Rateable rateObject;

	/** The period (in milliseconds) in which the measures are taken */
	private long period;

	/** The name of the variable to be measured */
	private String unit;

	/** The state if this rater: active or inactive */
	private boolean active;

	/**
	 * The transactions that are supposed to be monitored. If zero, then it
	 * assumed to be unlimited.
	 */
	private long targetTransactions;

	/**
	 * This constructor create this Rater as a Thread with the target object to
	 * be measured as a parameter.
	 * 
	 * @param targetObject
	 *            The object to be measured.
	 * @param period
	 *            The period in milliseconds between each measure.
	 */
	public Rater(Rateable targetObject, long period) {

		/* Variable initialization */
		this.rateObject = targetObject;
		this.period = period;
		this.unit = "transaction";
		this.active = true;
	}

	@Override
	public void run() {

		try {
			synchronized (this) {

				logger.info("Starting to meassure...");
				while (active) {
					/* The object property is measured as an initial value */
					long initValue = this.rateObject.getValue();

					/* We sleep for some time of period */
					wait(this.period);

					/* The final measure is performed */
					DecimalFormat mdf = new DecimalFormat("0.0");
					long currentValue = this.rateObject.getValue();
					float rate = ((float) (currentValue - initValue) / this.period) * 1000;
					String percentage = mdf
							.format(((double) currentValue / this.targetTransactions) * 100);
					double timeLeft = (double) (this.targetTransactions - currentValue)
							/ rate;

					String theTimeLeft;
					if (timeLeft < 60)
						theTimeLeft = mdf.format(timeLeft) + " segs left";
					else if (timeLeft / 60 < 60)
						theTimeLeft = mdf.format(timeLeft / 60) + " mins left";
					else
						theTimeLeft = mdf.format(timeLeft / 60 / 60)
								+ " hrs left";

					/* The rate is logged */
					logger.info("Rate at: " + mdf.format(rate) + " "
							+ this.unit + "/secs (" + percentage + "% - "
							+ theTimeLeft + ")");
				}
			}
		} catch (InterruptedException e) {
			logger.error("Interrupted thread!", e);
		}
	}

	/**
	 * This method is responsible for starting the thread and makes it active.
	 */
	public void startRater() {
		this.active = true;
		this.start();
	}

	public void suspendRater() {
		try {
			this.wait();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * This method is responsible of resuming the work of the Rater.
	 */
	public void resumeRater() {
		this.notify();
	}

	/**
	 * This method terminates the work of the rater.
	 */
	public void stopRater() {
		this.active = false;
	}

	public void setTargetTransaccionts(long targetTransactions) {
		this.targetTransactions = targetTransactions;
	}

}
